/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set sw=2 ts=2 et tw=80 : *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"mozilla/layers/CompositorBridgeParent.h"#include<stdio.h> // for fprintf, stdout#include<stdint.h> // for uint64_t#include<map> // for _Rb_tree_iterator, etc#include<utility> // for pair#include"LayerTransactionParent.h" // for LayerTransactionParent#include"RenderTrace.h" // for RenderTraceLayers#include"base/message_loop.h" // for MessageLoop#include"base/process.h" // for ProcessId#include"base/task.h" // for CancelableTask, etc#include"base/thread.h" // for Thread#include"gfxContext.h" // for gfxContext#include"gfxPlatform.h" // for gfxPlatform#include"TreeTraversal.h" // for ForEachNode#ifdef MOZ_WIDGET_GTK#include"gfxPlatformGtk.h" // for gfxPlatform#endif#include"gfxPrefs.h" // for gfxPrefs#include"mozilla/AutoRestore.h" // for AutoRestore#include"mozilla/ClearOnShutdown.h" // for ClearOnShutdown#include"mozilla/DebugOnly.h" // for DebugOnly#include"mozilla/dom/ContentParent.h"#include"mozilla/dom/TabParent.h"#include"mozilla/gfx/2D.h" // for DrawTarget#include"mozilla/gfx/GPUChild.h" // for GfxPrefValue#include"mozilla/gfx/Point.h" // for IntSize#include"mozilla/gfx/Rect.h" // for IntSize#include"mozilla/gfx/gfxVars.h" // for gfxVars#include"VRManager.h" // for VRManager#include"mozilla/ipc/Transport.h" // for Transport#include"mozilla/gfx/gfxVars.h"#include"mozilla/layers/AnimationHelper.h" // for CompositorAnimationStorage#include"mozilla/layers/APZCTreeManager.h" // for APZCTreeManager#include"mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent#include"mozilla/layers/APZThreadUtils.h" // for APZCTreeManager#include"mozilla/layers/AsyncCompositionManager.h"#include"mozilla/layers/BasicCompositor.h" // for BasicCompositor#include"mozilla/layers/Compositor.h" // for Compositor#include"mozilla/layers/CompositorManagerParent.h" // for CompositorManagerParent#include"mozilla/layers/CompositorOGL.h" // for CompositorOGL#include"mozilla/layers/CompositorThread.h"#include"mozilla/layers/CompositorTypes.h"#include"mozilla/layers/CompositorVsyncScheduler.h"#include"mozilla/layers/CrossProcessCompositorBridgeParent.h"#include"mozilla/layers/FrameUniformityData.h"#include"mozilla/layers/ImageBridgeParent.h"#include"mozilla/layers/LayerManagerComposite.h"#include"mozilla/layers/LayerManagerMLGPU.h"#include"mozilla/layers/LayerTreeOwnerTracker.h"#include"mozilla/layers/LayersTypes.h"#include"mozilla/layers/PLayerTransactionParent.h"#include"mozilla/layers/RemoteContentController.h"#include"mozilla/layers/WebRenderBridgeParent.h"#include"mozilla/layers/WebRenderCompositableHolder.h"#include"mozilla/layout/RenderFrameParent.h"#include"mozilla/webrender/WebRenderAPI.h"#include"mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService#include"mozilla/mozalloc.h" // for operator new, etc#include"mozilla/Telemetry.h"#ifdef MOZ_WIDGET_GTK#include"basic/X11BasicCompositor.h" // for X11BasicCompositor#endif#include"nsCOMPtr.h" // for already_AddRefed#include"nsDebug.h" // for NS_ASSERTION, etc#include"nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc#include"nsIWidget.h" // for nsIWidget#include"nsTArray.h" // for nsTArray#include"nsThreadUtils.h" // for NS_IsMainThread#include"nsXULAppAPI.h" // for XRE_GetIOMessageLoop#ifdef XP_WIN#include"mozilla/layers/CompositorD3D11.h"#endif#include"GeckoProfiler.h"#include"mozilla/ipc/ProtocolTypes.h"#include"mozilla/Unused.h"#include"mozilla/Hal.h"#include"mozilla/HalTypes.h"#include"mozilla/StaticPtr.h"#include"mozilla/Telemetry.h"#ifdef MOZ_GECKO_PROFILER#include"ProfilerMarkerPayload.h"#endif#include"mozilla/VsyncDispatcher.h"#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)#include"VsyncSource.h"#endif#include"mozilla/widget/CompositorWidget.h"#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING# include "mozilla/widget/CompositorWidgetParent.h"#endif#ifdef XP_WIN# include "mozilla/gfx/DeviceManagerDx.h"#endif#include"LayerScope.h"namespacemozilla{namespacelayers{usingnamespacemozilla::ipc;usingnamespacemozilla::gfx;usingnamespacestd;usingbase::ProcessId;usingbase::Thread;CompositorBridgeParentBase::CompositorBridgeParentBase(CompositorManagerParent*aManager):mCanSend(true),mCompositorManager(aManager){}CompositorBridgeParentBase::~CompositorBridgeParentBase(){}ProcessIdCompositorBridgeParentBase::GetChildProcessId(){returnOtherPid();}voidCompositorBridgeParentBase::NotifyNotUsed(PTextureParent*aTexture,uint64_taTransactionId){RefPtr<TextureHost>texture=TextureHost::AsTextureHost(aTexture);if(!texture){return;}if(!(texture->GetFlags()&TextureFlags::RECYCLE)){return;}uint64_ttextureId=TextureHost::GetTextureSerial(aTexture);mPendingAsyncMessage.push_back(OpNotifyNotUsed(textureId,aTransactionId));}voidCompositorBridgeParentBase::SendAsyncMessage(constInfallibleTArray<AsyncParentMessageData>&aMessage){Unused<<SendParentAsyncMessages(aMessage);}boolCompositorBridgeParentBase::AllocShmem(size_taSize,ipc::SharedMemory::SharedMemoryTypeaType,ipc::Shmem*aShmem){returnPCompositorBridgeParent::AllocShmem(aSize,aType,aShmem);}boolCompositorBridgeParentBase::AllocUnsafeShmem(size_taSize,ipc::SharedMemory::SharedMemoryTypeaType,ipc::Shmem*aShmem){returnPCompositorBridgeParent::AllocUnsafeShmem(aSize,aType,aShmem);}voidCompositorBridgeParentBase::DeallocShmem(ipc::Shmem&aShmem){PCompositorBridgeParent::DeallocShmem(aShmem);}base::ProcessIdCompositorBridgeParentBase::RemotePid(){returnOtherPid();}boolCompositorBridgeParentBase::StartSharingMetrics(ipc::SharedMemoryBasic::HandleaHandle,CrossProcessMutexHandleaMutexHandle,uint64_taLayersId,uint32_taApzcId){if(!mCanSend){returnfalse;}returnPCompositorBridgeParent::SendSharedCompositorFrameMetrics(aHandle,aMutexHandle,aLayersId,aApzcId);}boolCompositorBridgeParentBase::StopSharingMetrics(FrameMetrics::ViewIDaScrollId,uint32_taApzcId){if(!mCanSend){returnfalse;}returnPCompositorBridgeParent::SendReleaseSharedCompositorFrameMetrics(aScrollId,aApzcId);}CompositorBridgeParent::LayerTreeState::LayerTreeState():mApzcTreeManagerParent(nullptr),mParent(nullptr),mLayerManager(nullptr),mCrossProcessParent(nullptr),mLayerTree(nullptr),mUpdatedPluginDataAvailable(false){}CompositorBridgeParent::LayerTreeState::~LayerTreeState(){if(mController){mController->Destroy();}}typedefmap<uint64_t,CompositorBridgeParent::LayerTreeState>LayerTreeMap;LayerTreeMapsIndirectLayerTrees;StaticAutoPtr<mozilla::Monitor>sIndirectLayerTreesLock;staticvoidEnsureLayerTreeMapReady(){MOZ_ASSERT(NS_IsMainThread());if(!sIndirectLayerTreesLock){sIndirectLayerTreesLock=newMonitor("IndirectLayerTree");mozilla::ClearOnShutdown(&sIndirectLayerTreesLock);}}template<typenameLambda>inlinevoidCompositorBridgeParent::ForEachIndirectLayerTree(constLambda&aCallback){sIndirectLayerTreesLock->AssertCurrentThreadOwns();for(autoit=sIndirectLayerTrees.begin();it!=sIndirectLayerTrees.end();it++){LayerTreeState*state=&it->second;if(state->mParent==this){aCallback(state,it->first);}}}/** * A global map referencing each compositor by ID. * * This map is used by the ImageBridge protocol to trigger * compositions without having to keep references to the * compositor */typedefmap<uint64_t,CompositorBridgeParent*>CompositorMap;staticStaticAutoPtr<CompositorMap>sCompositorMap;voidCompositorBridgeParent::Setup(){EnsureLayerTreeMapReady();MOZ_ASSERT(!sCompositorMap);sCompositorMap=newCompositorMap;gfxPrefs::SetWebRenderProfilerEnabledChangeCallback([](constGfxPrefValue&aValue)->void{CompositorBridgeParent::SetWebRenderProfilerEnabled(aValue.get_bool());});}voidCompositorBridgeParent::Shutdown(){MOZ_ASSERT(sCompositorMap);MOZ_ASSERT(sCompositorMap->empty());sCompositorMap=nullptr;gfxPrefs::SetWebRenderProfilerEnabledChangeCallback(nullptr);}voidCompositorBridgeParent::FinishShutdown(){// TODO: this should be empty by now...sIndirectLayerTrees.clear();}staticvoidSetThreadPriority(){hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);}#ifdef COMPOSITOR_PERFORMANCE_WARNINGstaticint32_tCalculateCompositionFrameRate(){// Used when layout.frame_rate is -1. Needs to be kept in sync with// DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.// TODO: This should actually return the vsync rate.constint32_tdefaultFrameRate=60;int32_tcompositionFrameRatePref=gfxPrefs::LayersCompositionFrameRate();if(compositionFrameRatePref<0){// Use the same frame rate for composition as for layout.int32_tlayoutFrameRatePref=gfxPrefs::LayoutFrameRate();if(layoutFrameRatePref<0){// TODO: The main thread frame scheduling code consults the actual// monitor refresh rate in this case. We should do the same.returndefaultFrameRate;}returnlayoutFrameRatePref;}returncompositionFrameRatePref;}#endifstaticinlineMessageLoop*CompositorLoop(){returnCompositorThreadHolder::Loop();}CompositorBridgeParent::CompositorBridgeParent(CompositorManagerParent*aManager,CSSToLayoutDeviceScaleaScale,constTimeDuration&aVsyncRate,constCompositorOptions&aOptions,boolaUseExternalSurfaceSize,constgfx::IntSize&aSurfaceSize):CompositorBridgeParentBase(aManager),mWidget(nullptr),mScale(aScale),mVsyncRate(aVsyncRate),mIsTesting(false),mPendingTransaction(0),mPaused(false),mUseExternalSurfaceSize(aUseExternalSurfaceSize),mEGLSurfaceSize(aSurfaceSize),mOptions(aOptions),mPauseCompositionMonitor("PauseCompositionMonitor"),mResumeCompositionMonitor("ResumeCompositionMonitor"),mRootLayerTreeID(0),mOverrideComposeReadiness(false),mForceCompositionTask(nullptr),mCompositorScheduler(nullptr),mAnimationStorage(nullptr),mPaintTime(TimeDuration::Forever())#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK),mLastPluginUpdateLayerTreeId(0),mDeferPluginWindows(false),mPluginWindowsHidden(false)#endif{}voidCompositorBridgeParent::InitSameProcess(widget::CompositorWidget*aWidget,constuint64_t&aLayerTreeId){MOZ_ASSERT(XRE_IsParentProcess());MOZ_ASSERT(NS_IsMainThread());mWidget=aWidget;mRootLayerTreeID=aLayerTreeId;if(mOptions.UseAPZ()){mApzcTreeManager=newAPZCTreeManager();}Initialize();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvInitialize(constuint64_t&aRootLayerTreeId){mRootLayerTreeID=aRootLayerTreeId;Initialize();returnIPC_OK();}voidCompositorBridgeParent::Initialize(){MOZ_ASSERT(CompositorThread(),"The compositor thread must be Initialized before instanciating a CompositorBridgeParent.");mCompositorBridgeID=0;// FIXME: This holds on the the fact that right now the only thing that// can destroy this instance is initialized on the compositor thread after// this task has been processed.MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableFunction(&AddCompositor,this,&mCompositorBridgeID));CompositorLoop()->PostTask(NewRunnableFunction(SetThreadPriority));{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[mRootLayerTreeID].mParent=this;}LayerScope::SetPixelScale(mScale.scale);if(!mOptions.UseWebRender()){mCompositorScheduler=newCompositorVsyncScheduler(this,mWidget);}}uint64_tCompositorBridgeParent::RootLayerTreeId(){MOZ_ASSERT(mRootLayerTreeID);returnmRootLayerTreeID;}CompositorBridgeParent::~CompositorBridgeParent(){InfallibleTArray<PTextureParent*>textures;ManagedPTextureParent(textures);// We expect all textures to be destroyed by now.MOZ_DIAGNOSTIC_ASSERT(textures.Length()==0);for(unsignedinti=0;i<textures.Length();++i){RefPtr<TextureHost>tex=TextureHost::AsTextureHost(textures[i]);tex->DeallocateDeviceData();}}mozilla::ipc::IPCResultCompositorBridgeParent::RecvForceIsFirstPaint(){mCompositionManager->ForceIsFirstPaint();returnIPC_OK();}voidCompositorBridgeParent::StopAndClearResources(){if(mForceCompositionTask){mForceCompositionTask->Cancel();mForceCompositionTask=nullptr;}mPaused=true;// Ensure that the layer manager is destroyed before CompositorBridgeChild.if(mLayerManager){MonitorAutoLocklock(*sIndirectLayerTreesLock);ForEachIndirectLayerTree([this](LayerTreeState*lts,uint64_t)->void{mLayerManager->ClearCachedResources(lts->mRoot);lts->mLayerManager=nullptr;lts->mParent=nullptr;});mLayerManager->Destroy();mLayerManager=nullptr;mCompositionManager=nullptr;}if(mWrBridge){MonitorAutoLocklock(*sIndirectLayerTreesLock);ForEachIndirectLayerTree([](LayerTreeState*lts,uint64_t)->void{if(lts->mWrBridge){lts->mWrBridge->Destroy();lts->mWrBridge=nullptr;}lts->mParent=nullptr;});mWrBridge->Destroy();mWrBridge=nullptr;}if(mCompositor){mCompositor->DetachWidget();mCompositor->Destroy();mCompositor=nullptr;}// This must be destroyed now since it accesses the widget.if(mCompositorScheduler){mCompositorScheduler->Destroy();mCompositorScheduler=nullptr;}// After this point, it is no longer legal to access the widget.mWidget=nullptr;// Clear mAnimationStorage here to ensure that the compositor thread// still exists when we destroy it.mAnimationStorage=nullptr;}mozilla::ipc::IPCResultCompositorBridgeParent::RecvWillClose(){StopAndClearResources();returnIPC_OK();}voidCompositorBridgeParent::DeferredDestroy(){MOZ_ASSERT(!NS_IsMainThread());mSelfRef=nullptr;}mozilla::ipc::IPCResultCompositorBridgeParent::RecvPause(){PauseComposition();returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvResume(){ResumeComposition();returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvMakeSnapshot(constSurfaceDescriptor&aInSnapshot,constgfx::IntRect&aRect){RefPtr<DrawTarget>target=GetDrawTargetForDescriptor(aInSnapshot,gfx::BackendType::CAIRO);MOZ_ASSERT(target);if(!target){// We kill the content process rather than have it continue with an invalid// snapshot, that may be too harsh and we could decide to return some sort// of error to the child process and let it deal with it...returnIPC_FAIL_NO_REASON(this);}ForceComposeToTarget(target,&aRect);returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvWaitOnTransactionProcessed(){returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvFlushRendering(){if(gfxVars::UseWebRender()){mWrBridge->FlushRendering(/* aIsSync */true);returnIPC_OK();}if(mCompositorScheduler->NeedsComposite()){CancelCurrentCompositeTask();ForceComposeToTarget(nullptr);}returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvFlushRenderingAsync(){if(gfxVars::UseWebRender()){mWrBridge->FlushRendering(/* aIsSync */false);returnIPC_OK();}returnRecvFlushRendering();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvForcePresent(){// During the shutdown sequence mLayerManager may be nullif(mLayerManager){mLayerManager->ForcePresent();}returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvNotifyRegionInvalidated(constnsIntRegion&aRegion){if(mLayerManager){mLayerManager->AddInvalidRegion(aRegion);}returnIPC_OK();}voidCompositorBridgeParent::Invalidate(){if(mLayerManager&&mLayerManager->GetRoot()){mLayerManager->AddInvalidRegion(mLayerManager->GetRoot()->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());}}mozilla::ipc::IPCResultCompositorBridgeParent::RecvStartFrameTimeRecording(constint32_t&aBufferSize,uint32_t*aOutStartIndex){if(mLayerManager){*aOutStartIndex=mLayerManager->StartFrameTimeRecording(aBufferSize);}else{*aOutStartIndex=0;}returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvStopFrameTimeRecording(constuint32_t&aStartIndex,InfallibleTArray<float>*intervals){if(mLayerManager){mLayerManager->StopFrameTimeRecording(aStartIndex,*intervals);}returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvClearApproximatelyVisibleRegions(constuint64_t&aLayersId,constuint32_t&aPresShellId){ClearApproximatelyVisibleRegions(aLayersId,Some(aPresShellId));returnIPC_OK();}voidCompositorBridgeParent::ClearApproximatelyVisibleRegions(constuint64_t&aLayersId,constMaybe<uint32_t>&aPresShellId){if(mLayerManager){mLayerManager->ClearApproximatelyVisibleRegions(aLayersId,aPresShellId);// We need to recomposite to update the minimap.ScheduleComposition();}}mozilla::ipc::IPCResultCompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(constScrollableLayerGuid&aGuid,constCSSIntRegion&aRegion){if(mLayerManager){mLayerManager->UpdateApproximatelyVisibleRegion(aGuid,aRegion);// We need to recomposite to update the minimap.ScheduleComposition();}returnIPC_OK();}voidCompositorBridgeParent::ActorDestroy(ActorDestroyReasonwhy){mCanSend=false;StopAndClearResources();RemoveCompositor(mCompositorBridgeID);mCompositionManager=nullptr;if(mApzcTreeManager){mApzcTreeManager->ClearTree();mApzcTreeManager=nullptr;}{// scope lockMonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees.erase(mRootLayerTreeID);}// There are chances that the ref count reaches zero on the main thread shortly// after this function returns while some ipdl code still needs to run on// this thread.// We must keep the compositor parent alive untill the code handling message// reception is finished on this thread.mSelfRef=this;MessageLoop::current()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::DeferredDestroy",this,&CompositorBridgeParent::DeferredDestroy));}voidCompositorBridgeParent::ScheduleRenderOnCompositorThread(){MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::ScheduleComposition",this,&CompositorBridgeParent::ScheduleComposition));}voidCompositorBridgeParent::InvalidateOnCompositorThread(){MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::Invalidate",this,&CompositorBridgeParent::Invalidate));}voidCompositorBridgeParent::PauseComposition(){MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),"PauseComposition() can only be called on the compositor thread");MonitorAutoLocklock(mPauseCompositionMonitor);if(!mPaused){mPaused=true;if(!gfxVars::UseWebRender()){mCompositor->Pause();}else{mWrBridge->Pause();}TimeStampnow=TimeStamp::Now();DidComposite(now,now);}// if anyone's waiting to make sure that composition really got paused, tell themlock.NotifyAll();}voidCompositorBridgeParent::ResumeComposition(){MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),"ResumeComposition() can only be called on the compositor thread");MonitorAutoLocklock(mResumeCompositionMonitor);boolresumed=gfxVars::UseWebRender()?mWrBridge->Resume():mCompositor->Resume();if(!resumed){#ifdef MOZ_WIDGET_ANDROID// We can't get a surface. This could be because the activity changed between// the time resume was scheduled and now.__android_log_print(ANDROID_LOG_INFO,"CompositorBridgeParent","Unable to renew compositor surface; remaining in paused state");#endiflock.NotifyAll();return;}mPaused=false;Invalidate();mCompositorScheduler->ResumeComposition();// if anyone's waiting to make sure that composition really got resumed, tell themlock.NotifyAll();}voidCompositorBridgeParent::ForceComposition(){// Cancel the orientation changed state to force compositionmForceCompositionTask=nullptr;ScheduleRenderOnCompositorThread();}voidCompositorBridgeParent::CancelCurrentCompositeTask(){mCompositorScheduler->CancelCurrentCompositeTask();}voidCompositorBridgeParent::SetEGLSurfaceSize(intwidth,intheight){NS_ASSERTION(mUseExternalSurfaceSize,"Compositor created without UseExternalSurfaceSize provided");mEGLSurfaceSize.SizeTo(width,height);if(mCompositor){mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width,mEGLSurfaceSize.height));}}voidCompositorBridgeParent::ResumeCompositionAndResize(intwidth,intheight){SetEGLSurfaceSize(width,height);ResumeComposition();}/* * This will execute a pause synchronously, waiting to make sure that the compositor * really is paused. */voidCompositorBridgeParent::SchedulePauseOnCompositorThread(){MonitorAutoLocklock(mPauseCompositionMonitor);MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::PauseComposition",this,&CompositorBridgeParent::PauseComposition));// Wait until the pause has actually been processed by the compositor threadlock.Wait();}boolCompositorBridgeParent::ScheduleResumeOnCompositorThread(){MonitorAutoLocklock(mResumeCompositionMonitor);MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::ResumeComposition",this,&CompositorBridgeParent::ResumeComposition));// Wait until the resume has actually been processed by the compositor threadlock.Wait();return!mPaused;}boolCompositorBridgeParent::ScheduleResumeOnCompositorThread(intwidth,intheight){MonitorAutoLocklock(mResumeCompositionMonitor);MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod<int,int>("layers::CompositorBridgeParent::ResumeCompositionAndResize",this,&CompositorBridgeParent::ResumeCompositionAndResize,width,height));// Wait until the resume has actually been processed by the compositor threadlock.Wait();return!mPaused;}voidCompositorBridgeParent::ScheduleTask(already_AddRefed<CancelableRunnable>task,inttime){if(time==0){MessageLoop::current()->PostTask(Move(task));}else{MessageLoop::current()->PostDelayedTask(Move(task),time);}}voidCompositorBridgeParent::UpdatePaintTime(LayerTransactionParent*aLayerTree,constTimeDuration&aPaintTime){// We get a lot of paint timings for things with empty transactions.if(!mLayerManager||aPaintTime.ToMilliseconds()<1.0){return;}mLayerManager->SetPaintTime(aPaintTime);}voidCompositorBridgeParent::NotifyShadowTreeTransaction(uint64_taId,boolaIsFirstPaint,constFocusTarget&aFocusTarget,boolaScheduleComposite,uint32_taPaintSequenceNumber,boolaIsRepeatTransaction,boolaHitTestUpdate){if(!aIsRepeatTransaction&&mLayerManager&&mLayerManager->GetRoot()){// Process plugin data here to give time for them to update before the next// composition.boolpluginsUpdatedFlag=true;AutoResolveRefLayersresolve(mCompositionManager,this,nullptr,&pluginsUpdatedFlag);#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)// If plugins haven't been updated, stop waiting.if(!pluginsUpdatedFlag){mWaitForPluginsUntil=TimeStamp();mHaveBlockedForPlugins=false;}#endifif(mApzcTreeManager){mApzcTreeManager->UpdateFocusState(mRootLayerTreeID,aId,aFocusTarget);if(aHitTestUpdate){mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID,mLayerManager->GetRoot(),aIsFirstPaint,aId,aPaintSequenceNumber);}}mLayerManager->NotifyShadowTreeTransaction();}if(aScheduleComposite){ScheduleComposition();}}voidCompositorBridgeParent::ScheduleComposition(){MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());if(mPaused){return;}mCompositorScheduler->ScheduleComposition();}// Go down the composite layer tree, setting properties to match their// content-side counterparts./* static */voidCompositorBridgeParent::SetShadowProperties(Layer*aLayer){ForEachNode<ForwardIterator>(aLayer,[](Layer*layer){if(Layer*maskLayer=layer->GetMaskLayer()){SetShadowProperties(maskLayer);}for(size_ti=0;i<layer->GetAncestorMaskLayerCount();i++){SetShadowProperties(layer->GetAncestorMaskLayerAt(i));}// FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate.HostLayer*layerCompositor=layer->AsHostLayer();// Set the layerComposite's base transform to the layer's base transform.layerCompositor->SetShadowBaseTransform(layer->GetBaseTransform());layerCompositor->SetShadowTransformSetByAnimation(false);layerCompositor->SetShadowVisibleRegion(layer->GetVisibleRegion());layerCompositor->SetShadowClipRect(layer->GetClipRect());layerCompositor->SetShadowOpacity(layer->GetOpacity());layerCompositor->SetShadowOpacitySetByAnimation(false);});}voidCompositorBridgeParent::CompositeToTarget(DrawTarget*aTarget,constgfx::IntRect*aRect){AutoProfilerTracingtracing("Paint","Composite");AUTO_PROFILER_LABEL("CompositorBridgeParent::CompositeToTarget",GRAPHICS);MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),"Composite can only be called on the compositor thread");TimeStampstart=TimeStamp::Now();#ifdef COMPOSITOR_PERFORMANCE_WARNINGTimeDurationscheduleDelta=TimeStamp::Now()-mCompositorScheduler->GetExpectedComposeStartTime();if(scheduleDelta>TimeDuration::FromMilliseconds(2)||scheduleDelta<TimeDuration::FromMilliseconds(-2)){printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",scheduleDelta.ToMilliseconds());}#endifif(!CanComposite()){TimeStampend=TimeStamp::Now();DidComposite(start,end);return;}#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)if(!mWaitForPluginsUntil.IsNull()&&mWaitForPluginsUntil>start){mHaveBlockedForPlugins=true;ScheduleComposition();return;}#endif/* * AutoResolveRefLayers handles two tasks related to Windows and Linux * plugin window management: * 1) calculating if we have remote content in the view. If we do not have * remote content, all plugin windows for this CompositorBridgeParent (window) * can be hidden since we do not support plugins in chrome when running * under e10s. * 2) Updating plugin position, size, and clip. We do this here while the * remote layer tree is hooked up to to chrome layer tree. This is needed * since plugin clipping can depend on chrome (for example, due to tab modal * prompts). Updates in step 2 are applied via an async ipc message sent * to the main thread. */boolhasRemoteContent=false;boolupdatePluginsFlag=true;AutoResolveRefLayersresolve(mCompositionManager,this,&hasRemoteContent,&updatePluginsFlag);#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)// We do not support plugins in local content. When switching tabs// to local pages, hide every plugin associated with the window.if(!hasRemoteContent&&gfxVars::BrowserTabsRemoteAutostart()&&mCachedPluginData.Length()){Unused<<SendHideAllPlugins(GetWidget()->GetWidgetKey());mCachedPluginData.Clear();}#endifif(aTarget){mLayerManager->BeginTransactionWithDrawTarget(aTarget,*aRect);}else{mLayerManager->BeginTransaction();}SetShadowProperties(mLayerManager->GetRoot());if(mForceCompositionTask&&!mOverrideComposeReadiness){if(mCompositionManager->ReadyForCompose()){mForceCompositionTask->Cancel();mForceCompositionTask=nullptr;}else{return;}}mCompositionManager->ComputeRotation();TimeStamptime=mIsTesting?mTestTime:mCompositorScheduler->GetLastComposeTime();boolrequestNextFrame=mCompositionManager->TransformShadowTree(time,mVsyncRate);if(requestNextFrame){ScheduleComposition();#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)// If we have visible windowed plugins then we need to wait for content (and// then the plugins) to have been updated by the active animation.if(!mPluginWindowsHidden&&mCachedPluginData.Length()){mWaitForPluginsUntil=mCompositorScheduler->GetLastComposeTime()+(mVsyncRate*2);}#endif}RenderTraceLayers(mLayerManager->GetRoot(),"0000");#ifdef MOZ_DUMP_PAINTINGif(gfxPrefs::DumpHostLayers()){printf_stderr("Painting --- compositing layer tree:\n");mLayerManager->Dump(/* aSorted = */true);}#endifmLayerManager->SetDebugOverlayWantsNextFrame(false);mLayerManager->EndTransaction(time);if(!aTarget){TimeStampend=TimeStamp::Now();DidComposite(start,end);}// We're not really taking advantage of the stored composite-again-time here.// We might be able to skip the next few composites altogether. However,// that's a bit complex to implement and we'll get most of the advantage// by skipping compositing when we detect there's nothing invalid. This is why// we do "composite until" rather than "composite again at".//// TODO(bug 1328602) Figure out what we should do here with the render thread.if(!mLayerManager->GetCompositeUntilTime().IsNull()||mLayerManager->DebugOverlayWantsNextFrame()){ScheduleComposition();}#ifdef COMPOSITOR_PERFORMANCE_WARNINGTimeDurationexecutionTime=TimeStamp::Now()-mCompositorScheduler->GetLastComposeTime();TimeDurationframeBudget=TimeDuration::FromMilliseconds(15);int32_tframeRate=CalculateCompositionFrameRate();if(frameRate>0){frameBudget=TimeDuration::FromSeconds(1.0/frameRate);}if(executionTime>frameBudget){printf_stderr("Compositor: Composite execution took %4.1f ms\n",executionTime.ToMilliseconds());}#endif// 0 -> Full-tilt compositeif(gfxPrefs::LayersCompositionFrameRate()==0||mLayerManager->AlwaysScheduleComposite()){// Special full-tilt composite mode for performance testingScheduleComposition();}// TODO(bug 1328602) Need an equivalent that works with the rende thread.mLayerManager->SetCompositionTime(TimeStamp());mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,start);}mozilla::ipc::IPCResultCompositorBridgeParent::RecvRemotePluginsReady(){#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)mWaitForPluginsUntil=TimeStamp();if(mHaveBlockedForPlugins){mHaveBlockedForPlugins=false;ForceComposeToTarget(nullptr);}else{ScheduleComposition();}returnIPC_OK();#elseNS_NOTREACHED("CompositorBridgeParent::RecvRemotePluginsReady calls ""unexpected on this platform.");returnIPC_FAIL_NO_REASON(this);#endif}voidCompositorBridgeParent::ForceComposeToTarget(DrawTarget*aTarget,constgfx::IntRect*aRect){AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget",GRAPHICS);AutoRestore<bool>override(mOverrideComposeReadiness);mOverrideComposeReadiness=true;mCompositorScheduler->ForceComposeToTarget(aTarget,aRect);}PAPZCTreeManagerParent*CompositorBridgeParent::AllocPAPZCTreeManagerParent(constuint64_t&aLayersId){// We should only ever get this if APZ is enabled in this compositor.MOZ_ASSERT(mOptions.UseAPZ());// The main process should pass in 0 because we assume mRootLayerTreeIDMOZ_ASSERT(aLayersId==0);// This message doubles as initializationMOZ_ASSERT(!mApzcTreeManager);mApzcTreeManager=newAPZCTreeManager();MonitorAutoLocklock(*sIndirectLayerTreesLock);CompositorBridgeParent::LayerTreeState&state=sIndirectLayerTrees[mRootLayerTreeID];MOZ_ASSERT(state.mParent);MOZ_ASSERT(!state.mApzcTreeManagerParent);state.mApzcTreeManagerParent=newAPZCTreeManagerParent(mRootLayerTreeID,state.mParent->GetAPZCTreeManager());returnstate.mApzcTreeManagerParent;}boolCompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent*aActor){deleteaActor;returntrue;}PAPZParent*CompositorBridgeParent::AllocPAPZParent(constuint64_t&aLayersId){// The main process should pass in 0 because we assume mRootLayerTreeIDMOZ_ASSERT(aLayersId==0);RemoteContentController*controller=newRemoteContentController();// Increment the controller's refcount before we return it. This will keep the// controller alive until it is released by IPDL in DeallocPAPZParent.controller->AddRef();MonitorAutoLocklock(*sIndirectLayerTreesLock);CompositorBridgeParent::LayerTreeState&state=sIndirectLayerTrees[mRootLayerTreeID];MOZ_ASSERT(!state.mController);state.mController=controller;returncontroller;}boolCompositorBridgeParent::DeallocPAPZParent(PAPZParent*aActor){RemoteContentController*controller=static_cast<RemoteContentController*>(aActor);controller->Release();returntrue;}RefPtr<APZCTreeManager>CompositorBridgeParent::GetAPZCTreeManager(){returnmApzcTreeManager;}CompositorBridgeParent*CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(constuint64_t&aLayersId){MonitorAutoLocklock(*sIndirectLayerTreesLock);returnsIndirectLayerTrees[aLayersId].mParent;}boolCompositorBridgeParent::CanComposite(){returnmLayerManager&&mLayerManager->GetRoot()&&!mPaused;}voidCompositorBridgeParent::ScheduleRotationOnCompositorThread(constTargetConfig&aTargetConfig,boolaIsFirstPaint){MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());if(!aIsFirstPaint&&!mCompositionManager->IsFirstPaint()&&mCompositionManager->RequiresReorientation(aTargetConfig.orientation())){if(mForceCompositionTask!=nullptr){mForceCompositionTask->Cancel();}RefPtr<CancelableRunnable>task=NewCancelableRunnableMethod("layers::CompositorBridgeParent::ForceComposition",this,&CompositorBridgeParent::ForceComposition);mForceCompositionTask=task;ScheduleTask(task.forget(),gfxPrefs::OrientationSyncMillis());}}voidCompositorBridgeParent::ShadowLayersUpdated(LayerTransactionParent*aLayerTree,constTransactionInfo&aInfo,boolaHitTestUpdate){constTargetConfig&targetConfig=aInfo.targetConfig();ScheduleRotationOnCompositorThread(targetConfig,aInfo.isFirstPaint());// Instruct the LayerManager to update its render bounds now. Since all the orientation// change, dimension change would be done at the stage, update the size here is free of// race condition.mLayerManager->UpdateRenderBounds(targetConfig.naturalBounds());mLayerManager->SetRegionToClear(targetConfig.clearRegion());if(mLayerManager->GetCompositor()){mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());}mCompositionManager->Updated(aInfo.isFirstPaint(),targetConfig);Layer*root=aLayerTree->GetRoot();mLayerManager->SetRoot(root);if(mApzcTreeManager&&!aInfo.isRepeatTransaction()){mApzcTreeManager->UpdateFocusState(mRootLayerTreeID,mRootLayerTreeID,aInfo.focusTarget());if(aHitTestUpdate){AutoResolveRefLayersresolve(mCompositionManager);mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID,root,aInfo.isFirstPaint(),mRootLayerTreeID,aInfo.paintSequenceNumber());}}// The transaction ID might get reset to 1 if the page gets reloaded, see// https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41// Otherwise, it should be continually increasing.MOZ_ASSERT(aInfo.id()==1||aInfo.id()>mPendingTransaction);mPendingTransaction=aInfo.id();if(root){SetShadowProperties(root);}if(aInfo.scheduleComposite()){ScheduleComposition();if(mPaused){TimeStampnow=TimeStamp::Now();DidComposite(now,now);}}mLayerManager->NotifyShadowTreeTransaction();}voidCompositorBridgeParent::ForceComposite(LayerTransactionParent*aLayerTree){ScheduleComposition();}boolCompositorBridgeParent::SetTestSampleTime(constuint64_t&aId,constTimeStamp&aTime){if(aTime.IsNull()){returnfalse;}mIsTesting=true;mTestTime=aTime;booltestComposite=mCompositionManager&&mCompositorScheduler->NeedsComposite();// Update but only if we were already scheduled to animateif(testComposite){AutoResolveRefLayersresolve(mCompositionManager);boolrequestNextFrame=mCompositionManager->TransformShadowTree(aTime,mVsyncRate);if(!requestNextFrame){CancelCurrentCompositeTask();// Pretend we composited in case someone is wating for this event.TimeStampnow=TimeStamp::Now();DidComposite(now,now);}}returntrue;}voidCompositorBridgeParent::LeaveTestMode(constuint64_t&aId){mIsTesting=false;}voidCompositorBridgeParent::ApplyAsyncProperties(LayerTransactionParent*aLayerTree){// NOTE: This should only be used for testing. For example, when mIsTesting is// true or when called from test-only methods like// LayerTransactionParent::RecvGetAnimationTransform.// Synchronously update the layer treeif(aLayerTree->GetRoot()){AutoResolveRefLayersresolve(mCompositionManager);SetShadowProperties(mLayerManager->GetRoot());TimeStamptime=mIsTesting?mTestTime:mCompositorScheduler->GetLastComposeTime();boolrequestNextFrame=mCompositionManager->TransformShadowTree(time,mVsyncRate,AsyncCompositionManager::TransformsToSkip::APZ);if(!requestNextFrame){CancelCurrentCompositeTask();// Pretend we composited in case someone is waiting for this event.TimeStampnow=TimeStamp::Now();DidComposite(now,now);}}}CompositorAnimationStorage*CompositorBridgeParent::GetAnimationStorage(constuint64_t&aId){MOZ_ASSERT(aId==0);if(!mAnimationStorage){mAnimationStorage=newCompositorAnimationStorage();}returnmAnimationStorage;}mozilla::ipc::IPCResultCompositorBridgeParent::RecvGetFrameUniformity(FrameUniformityData*aOutData){mCompositionManager->GetFrameUniformity(aOutData);returnIPC_OK();}voidCompositorBridgeParent::FlushApzRepaints(constuint64_t&aLayersId){MOZ_ASSERT(mApzcTreeManager);uint64_tlayersId=aLayersId;if(layersId==0){// The request is coming from the parent-process layer tree, so we should// use the compositor's root layer tree id.layersId=mRootLayerTreeID;}RefPtr<CompositorBridgeParent>self=this;APZThreadUtils::RunOnControllerThread(NS_NewRunnableFunction("layers::CompositorBridgeParent::FlushApzRepaints",[=](){self->mApzcTreeManager->FlushApzRepaints(layersId);}));}voidCompositorBridgeParent::GetAPZTestData(constuint64_t&aLayersId,APZTestData*aOutData){MOZ_ASSERT(aLayersId==0||aLayersId==mRootLayerTreeID);MonitorAutoLocklock(*sIndirectLayerTreesLock);*aOutData=sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;}voidCompositorBridgeParent::SetConfirmedTargetAPZC(constuint64_t&aLayersId,constuint64_t&aInputBlockId,constnsTArray<ScrollableLayerGuid>&aTargets){if(!mApzcTreeManager){return;}// Need to specifically bind this since it's overloaded.void(APZCTreeManager::*setTargetApzcFunc)(uint64_t,constnsTArray<ScrollableLayerGuid>&)=&APZCTreeManager::SetTargetAPZC;RefPtr<Runnable>task=NewRunnableMethod<uint64_t,StoreCopyPassByConstLRef<nsTArray<ScrollableLayerGuid>>>("layers::CompositorBridgeParent::SetConfirmedTargetAPZC",mApzcTreeManager.get(),setTargetApzcFunc,aInputBlockId,aTargets);APZThreadUtils::RunOnControllerThread(task.forget());}voidCompositorBridgeParent::InitializeLayerManager(constnsTArray<LayersBackend>&aBackendHints){NS_ASSERTION(!mLayerManager,"Already initialised mLayerManager");NS_ASSERTION(!mCompositor,"Already initialised mCompositor");if(!InitializeAdvancedLayers(aBackendHints,nullptr)){mCompositor=NewCompositor(aBackendHints);if(!mCompositor){return;}mLayerManager=newLayerManagerComposite(mCompositor);}mLayerManager->SetCompositorBridgeID(mCompositorBridgeID);MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[mRootLayerTreeID].mLayerManager=mLayerManager;}boolCompositorBridgeParent::InitializeAdvancedLayers(constnsTArray<LayersBackend>&aBackendHints,TextureFactoryIdentifier*aOutIdentifier){#ifdef XP_WINif(!mOptions.UseAdvancedLayers()){returnfalse;}RefPtr<LayerManagerMLGPU>manager=newLayerManagerMLGPU(mWidget);if(!manager->Initialize()){returnfalse;}if(aOutIdentifier){*aOutIdentifier=manager->GetTextureFactoryIdentifier();}mLayerManager=manager;returntrue;#elsereturnfalse;#endif}RefPtr<Compositor>CompositorBridgeParent::NewCompositor(constnsTArray<LayersBackend>&aBackendHints){for(size_ti=0;i<aBackendHints.Length();++i){RefPtr<Compositor>compositor;if(aBackendHints[i]==LayersBackend::LAYERS_OPENGL){compositor=newCompositorOGL(this,mWidget,mEGLSurfaceSize.width,mEGLSurfaceSize.height,mUseExternalSurfaceSize);}elseif(aBackendHints[i]==LayersBackend::LAYERS_BASIC){#ifdef MOZ_WIDGET_GTKif(gfxVars::UseXRender()){compositor=newX11BasicCompositor(this,mWidget);}else#endif{compositor=newBasicCompositor(this,mWidget);}#ifdef XP_WIN}elseif(aBackendHints[i]==LayersBackend::LAYERS_D3D11){compositor=newCompositorD3D11(this,mWidget);#endif}nsCStringfailureReason;if(compositor&&compositor->Initialize(&failureReason)){if(failureReason.IsEmpty()){failureReason="SUCCESS";}// should only report success hereif(aBackendHints[i]==LayersBackend::LAYERS_OPENGL){Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID,failureReason);}#ifdef XP_WINelseif(aBackendHints[i]==LayersBackend::LAYERS_D3D11){Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID,failureReason);}#endifreturncompositor;}// report any failure reasons hereif(aBackendHints[i]==LayersBackend::LAYERS_OPENGL){gfxCriticalNote<<"[OPENGL] Failed to init compositor with reason: "<<failureReason.get();Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID,failureReason);}#ifdef XP_WINelseif(aBackendHints[i]==LayersBackend::LAYERS_D3D11){gfxCriticalNote<<"[D3D11] Failed to init compositor with reason: "<<failureReason.get();Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID,failureReason);}#endif}returnnullptr;}PLayerTransactionParent*CompositorBridgeParent::AllocPLayerTransactionParent(constnsTArray<LayersBackend>&aBackendHints,constuint64_t&aId){MOZ_ASSERT(aId==0);InitializeLayerManager(aBackendHints);if(!mLayerManager){NS_WARNING("Failed to initialise Compositor");LayerTransactionParent*p=newLayerTransactionParent(nullptr,this,0);p->AddIPDLReference();returnp;}mCompositionManager=newAsyncCompositionManager(this,mLayerManager);LayerTransactionParent*p=newLayerTransactionParent(mLayerManager,this,0);p->AddIPDLReference();returnp;}boolCompositorBridgeParent::DeallocPLayerTransactionParent(PLayerTransactionParent*actor){static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();returntrue;}CompositorBridgeParent*CompositorBridgeParent::GetCompositorBridgeParent(uint64_tid){CompositorMap::iteratorit=sCompositorMap->find(id);returnit!=sCompositorMap->end()?it->second:nullptr;}voidCompositorBridgeParent::AddCompositor(CompositorBridgeParent*compositor,uint64_t*outID){staticuint64_tsNextID=1;++sNextID;(*sCompositorMap)[sNextID]=compositor;*outID=sNextID;}CompositorBridgeParent*CompositorBridgeParent::RemoveCompositor(uint64_tid){CompositorMap::iteratorit=sCompositorMap->find(id);if(it==sCompositorMap->end()){returnnullptr;}CompositorBridgeParent*retval=it->second;sCompositorMap->erase(it);returnretval;}voidCompositorBridgeParent::NotifyVsync(constTimeStamp&aTimeStamp,constuint64_t&aLayersId){MOZ_ASSERT(XRE_GetProcessType()==GeckoProcessType_GPU);MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());MonitorAutoLocklock(*sIndirectLayerTreesLock);autoit=sIndirectLayerTrees.find(aLayersId);if(it==sIndirectLayerTrees.end())return;CompositorBridgeParent*cbp=it->second.mParent;if(!cbp||!cbp->mWidget)return;RefPtr<VsyncObserver>obs=cbp->mWidget->GetVsyncObserver();if(!obs)return;obs->NotifyVsync(aTimeStamp);}mozilla::ipc::IPCResultCompositorBridgeParent::RecvNotifyChildCreated(constuint64_t&child,CompositorOptions*aOptions){MonitorAutoLocklock(*sIndirectLayerTreesLock);NotifyChildCreated(child);*aOptions=mOptions;returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvNotifyChildRecreated(constuint64_t&aChild,CompositorOptions*aOptions){MonitorAutoLocklock(*sIndirectLayerTreesLock);if(sIndirectLayerTrees.find(aChild)!=sIndirectLayerTrees.end()){// Invalid to register the same layer tree twice.returnIPC_FAIL_NO_REASON(this);}NotifyChildCreated(aChild);*aOptions=mOptions;returnIPC_OK();}voidCompositorBridgeParent::NotifyChildCreated(uint64_taChild){sIndirectLayerTreesLock->AssertCurrentThreadOwns();sIndirectLayerTrees[aChild].mParent=this;sIndirectLayerTrees[aChild].mLayerManager=mLayerManager;}mozilla::ipc::IPCResultCompositorBridgeParent::RecvMapAndNotifyChildCreated(constuint64_t&aChild,constbase::ProcessId&aOwnerPid,CompositorOptions*aOptions){// We only use this message when the remote compositor is in the GPU process.// It is harmless to call it, though.MOZ_ASSERT(XRE_IsGPUProcess());LayerTreeOwnerTracker::Get()->Map(aChild,aOwnerPid);MonitorAutoLocklock(*sIndirectLayerTreesLock);NotifyChildCreated(aChild);*aOptions=mOptions;returnIPC_OK();}mozilla::ipc::IPCResultCompositorBridgeParent::RecvAdoptChild(constuint64_t&child){APZCTreeManagerParent*parent;{MonitorAutoLocklock(*sIndirectLayerTreesLock);// We currently don't support adopting children from one compositor to// another if the two compositors don't have the same options.MOZ_ASSERT(sIndirectLayerTrees[child].mParent->mOptions==mOptions);NotifyChildCreated(child);if(sIndirectLayerTrees[child].mLayerTree){sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager);// Trigger composition to handle a case that mLayerTree was not composited yet// by previous CompositorBridgeParent, since nsRefreshDriver might wait composition complete.ScheduleComposition();}if(mWrBridge&&sIndirectLayerTrees[child].mWrBridge){sIndirectLayerTrees[child].mWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),mWrBridge->GetWebRenderAPI(),mWrBridge->CompositableHolder(),GetAnimationStorage(0));// Pretend we composited, since parent CompositorBridgeParent was replaced.CrossProcessCompositorBridgeParent*cpcp=sIndirectLayerTrees[child].mCrossProcessParent;if(cpcp){TimeStampnow=TimeStamp::Now();cpcp->DidComposite(child,now,now);}}parent=sIndirectLayerTrees[child].mApzcTreeManagerParent;}if(mApzcTreeManager&&parent){parent->ChildAdopted(mApzcTreeManager);}returnIPC_OK();}PWebRenderBridgeParent*CompositorBridgeParent::AllocPWebRenderBridgeParent(constwr::PipelineId&aPipelineId,constLayoutDeviceIntSize&aSize,TextureFactoryIdentifier*aTextureFactoryIdentifier,uint32_t*aIdNamespace){#ifndef MOZ_BUILD_WEBRENDER// Extra guard since this in the parent process and we don't want a malicious// child process invoking this codepath before it's readyMOZ_RELEASE_ASSERT(false);#endifMOZ_ASSERT(wr::AsUint64(aPipelineId)==mRootLayerTreeID);MOZ_ASSERT(!mWrBridge);MOZ_ASSERT(!mCompositor);MOZ_ASSERT(!mCompositorScheduler);MOZ_ASSERT(mWidget);RefPtr<widget::CompositorWidget>widget=mWidget;RefPtr<wr::WebRenderAPI>api=wr::WebRenderAPI::Create(gfxPrefs::WebRenderProfilerEnabled(),this,Move(widget),aSize);RefPtr<WebRenderCompositableHolder>holder=newWebRenderCompositableHolder(WebRenderBridgeParent::AllocIdNameSpace());MOZ_ASSERT(api);// TODO have a fallbackapi->SetRootPipeline(aPipelineId);RefPtr<CompositorAnimationStorage>animStorage=GetAnimationStorage(0);mWrBridge=newWebRenderBridgeParent(this,aPipelineId,mWidget,nullptr,Move(api),Move(holder),Move(animStorage));*aIdNamespace=mWrBridge->GetIdNameSpace();mCompositorScheduler=mWrBridge->CompositorScheduler();MOZ_ASSERT(mCompositorScheduler);mWrBridge.get()->AddRef();// IPDL referenceMonitorAutoLocklock(*sIndirectLayerTreesLock);MOZ_ASSERT(sIndirectLayerTrees[mRootLayerTreeID].mWrBridge==nullptr);sIndirectLayerTrees[mRootLayerTreeID].mWrBridge=mWrBridge;*aTextureFactoryIdentifier=mWrBridge->GetTextureFactoryIdentifier();returnmWrBridge;}boolCompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent*aActor){#ifndef MOZ_BUILD_WEBRENDER// Extra guard since this in the parent process and we don't want a malicious// child process invoking this codepath before it's readyMOZ_RELEASE_ASSERT(false);#endifWebRenderBridgeParent*parent=static_cast<WebRenderBridgeParent*>(aActor);{MonitorAutoLocklock(*sIndirectLayerTreesLock);autoit=sIndirectLayerTrees.find(parent->PipelineId().mHandle);if(it!=sIndirectLayerTrees.end()){it->second.mWrBridge=nullptr;}}parent->Release();// IPDL referencereturntrue;}RefPtr<WebRenderBridgeParent>CompositorBridgeParent::GetWebRenderBridgeParent()const{returnmWrBridge;}Maybe<TimeStamp>CompositorBridgeParent::GetTestingTimeStamp()const{returnmIsTesting?Some(mTestTime):Nothing();}voidCompositorBridgeParent::SetWebRenderProfilerEnabled(boolaEnabled){MonitorAutoLocklock(*sIndirectLayerTreesLock);for(autoit=sIndirectLayerTrees.begin();it!=sIndirectLayerTrees.end();it++){LayerTreeState*state=&it->second;if(state->mWrBridge){state->mWrBridge->SetWebRenderProfilerEnabled(aEnabled);}}}voidEraseLayerState(uint64_taId){MonitorAutoLocklock(*sIndirectLayerTreesLock);autoiter=sIndirectLayerTrees.find(aId);if(iter!=sIndirectLayerTrees.end()){CompositorBridgeParent*parent=iter->second.mParent;if(parent){parent->ClearApproximatelyVisibleRegions(aId,Nothing());}sIndirectLayerTrees.erase(iter);}}/*static*/voidCompositorBridgeParent::DeallocateLayerTreeId(uint64_taId){MOZ_ASSERT(NS_IsMainThread());// Here main thread notifies compositor to remove an element from// sIndirectLayerTrees. This removed element might be queried soon.// Checking the elements of sIndirectLayerTrees exist or not before using.if(!CompositorLoop()){gfxCriticalError()<<"Attempting to post to a invalid Compositor Loop";return;}CompositorLoop()->PostTask(NewRunnableFunction(&EraseLayerState,aId));}staticvoidUpdateControllerForLayersId(uint64_taLayersId,GeckoContentController*aController){// Adopt ref given to us by SetControllerForLayerTree()MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aLayersId].mController=already_AddRefed<GeckoContentController>(aController);}ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(APZCTreeManager*aApzctm,uint64_taLayersId,Layer*aRoot,GeckoContentController*aController):mLayersId(aLayersId){EnsureLayerTreeMapReady();MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aLayersId].mRoot=aRoot;sIndirectLayerTrees[aLayersId].mController=aController;}ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration(){MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees.erase(mLayersId);}/*static*/voidCompositorBridgeParent::SetControllerForLayerTree(uint64_taLayersId,GeckoContentController*aController){// This ref is adopted by UpdateControllerForLayersId().aController->AddRef();CompositorLoop()->PostTask(NewRunnableFunction(&UpdateControllerForLayersId,aLayersId,aController));}/*static*/already_AddRefed<APZCTreeManager>CompositorBridgeParent::GetAPZCTreeManager(uint64_taLayersId){EnsureLayerTreeMapReady();MonitorAutoLocklock(*sIndirectLayerTreesLock);LayerTreeMap::iteratorcit=sIndirectLayerTrees.find(aLayersId);if(sIndirectLayerTrees.end()==cit){returnnullptr;}LayerTreeState*lts=&cit->second;RefPtr<APZCTreeManager>apzctm=lts->mParent?lts->mParent->mApzcTreeManager.get():nullptr;returnapzctm.forget();}staticvoidInsertVsyncProfilerMarker(TimeStampaVsyncTimestamp){#ifdef MOZ_GECKO_PROFILERMOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());profiler_add_marker("VsyncTimestamp",MakeUnique<VsyncMarkerPayload>(aVsyncTimestamp));#endif}/*static */voidCompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStampaVsyncTimestamp){// Called in the vsync threadif(profiler_is_active()&&CompositorThreadHolder::IsActive()){CompositorLoop()->PostTask(NewRunnableFunction(InsertVsyncProfilerMarker,aVsyncTimestamp));}}widget::PCompositorWidgetParent*CompositorBridgeParent::AllocPCompositorWidgetParent(constCompositorWidgetInitData&aInitData){#if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)if(mWidget){// Should not create two widgets on the same compositor.returnnullptr;}widget::CompositorWidgetParent*widget=newwidget::CompositorWidgetParent(aInitData,mOptions);widget->AddRef();// Sending the constructor acts as initialization as well.mWidget=widget;returnwidget;#elsereturnnullptr;#endif}boolCompositorBridgeParent::DeallocPCompositorWidgetParent(PCompositorWidgetParent*aActor){#if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)static_cast<widget::CompositorWidgetParent*>(aActor)->Release();returntrue;#elsereturnfalse;#endif}boolCompositorBridgeParent::IsPendingComposite(){MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());if(!mCompositor){returnfalse;}returnmCompositor->IsPendingComposite();}voidCompositorBridgeParent::FinishPendingComposite(){MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());if(!mCompositor){return;}returnmCompositor->FinishPendingComposite();}CompositorController*CompositorBridgeParent::LayerTreeState::GetCompositorController()const{returnmParent;}MetricsSharingController*CompositorBridgeParent::LayerTreeState::CrossProcessSharingController()const{returnmCrossProcessParent;}MetricsSharingController*CompositorBridgeParent::LayerTreeState::InProcessSharingController()const{returnmParent;}voidCompositorBridgeParent::DidComposite(TimeStamp&aCompositeStart,TimeStamp&aCompositeEnd){if(mWrBridge){NotifyDidComposite(mWrBridge->FlushPendingTransactionIds(),aCompositeStart,aCompositeEnd);}else{NotifyDidComposite(mPendingTransaction,aCompositeStart,aCompositeEnd);mPendingTransaction=0;}}voidCompositorBridgeParent::NotifyDidCompositeToPipeline(constwr::PipelineId&aPipelineId,constwr::Epoch&aEpoch,TimeStamp&aCompositeStart,TimeStamp&aCompositeEnd){if(!mWrBridge){return;}mWrBridge->CompositableHolder()->Update(aPipelineId,aEpoch);if(mPaused){return;}if(mWrBridge->PipelineId()==aPipelineId){uint64_ttransactionId=mWrBridge->FlushTransactionIdsForEpoch(aEpoch);Unused<<SendDidComposite(0,transactionId,aCompositeStart,aCompositeEnd);nsTArray<ImageCompositeNotificationInfo>notifications;mWrBridge->ExtractImageCompositeNotifications(¬ifications);if(!notifications.IsEmpty()){Unused<<ImageBridgeParent::NotifyImageComposites(notifications);}return;}MonitorAutoLocklock(*sIndirectLayerTreesLock);ForEachIndirectLayerTree([&](LayerTreeState*lts,constuint64_t&aLayersId)->void{if(lts->mCrossProcessParent&<s->mWrBridge&<s->mWrBridge->PipelineId()==aPipelineId){CrossProcessCompositorBridgeParent*cpcp=lts->mCrossProcessParent;uint64_ttransactionId=lts->mWrBridge->FlushTransactionIdsForEpoch(aEpoch);Unused<<cpcp->SendDidComposite(aLayersId,transactionId,aCompositeStart,aCompositeEnd);}});}voidCompositorBridgeParent::NotifyDidComposite(uint64_taTransactionId,TimeStamp&aCompositeStart,TimeStamp&aCompositeEnd){Unused<<SendDidComposite(0,aTransactionId,aCompositeStart,aCompositeEnd);if(mLayerManager){nsTArray<ImageCompositeNotificationInfo>notifications;mLayerManager->ExtractImageCompositeNotifications(¬ifications);if(!notifications.IsEmpty()){Unused<<ImageBridgeParent::NotifyImageComposites(notifications);}}if(mWrBridge){nsTArray<ImageCompositeNotificationInfo>notifications;mWrBridge->ExtractImageCompositeNotifications(¬ifications);if(!notifications.IsEmpty()){Unused<<ImageBridgeParent::NotifyImageComposites(notifications);}}MonitorAutoLocklock(*sIndirectLayerTreesLock);ForEachIndirectLayerTree([&](LayerTreeState*lts,constuint64_t&aLayersId)->void{if(lts->mCrossProcessParent&<s->mParent==this){CrossProcessCompositorBridgeParent*cpcp=lts->mCrossProcessParent;cpcp->DidComposite(aLayersId,aCompositeStart,aCompositeEnd);}});}voidCompositorBridgeParent::InvalidateRemoteLayers(){MOZ_ASSERT(CompositorLoop()==MessageLoop::current());Unused<<PCompositorBridgeParent::SendInvalidateLayers(0);MonitorAutoLocklock(*sIndirectLayerTreesLock);ForEachIndirectLayerTree([](LayerTreeState*lts,constuint64_t&aLayersId)->void{if(lts->mCrossProcessParent){CrossProcessCompositorBridgeParent*cpcp=lts->mCrossProcessParent;Unused<<cpcp->SendInvalidateLayers(aLayersId);}});}voidUpdateIndirectTree(uint64_taId,Layer*aRoot,constTargetConfig&aTargetConfig){MonitorAutoLocklock(*sIndirectLayerTreesLock);sIndirectLayerTrees[aId].mRoot=aRoot;sIndirectLayerTrees[aId].mTargetConfig=aTargetConfig;}/* static */CompositorBridgeParent::LayerTreeState*CompositorBridgeParent::GetIndirectShadowTree(uint64_taId){MonitorAutoLocklock(*sIndirectLayerTreesLock);LayerTreeMap::iteratorcit=sIndirectLayerTrees.find(aId);if(sIndirectLayerTrees.end()==cit){returnnullptr;}return&cit->second;}staticCompositorBridgeParent::LayerTreeState*GetStateForRoot(uint64_taContentLayersId,constMonitorAutoLock&aProofOfLock){CompositorBridgeParent::LayerTreeState*state=nullptr;LayerTreeMap::iteratoritr=sIndirectLayerTrees.find(aContentLayersId);if(sIndirectLayerTrees.end()!=itr){state=&itr->second;}// |state| is the state for the content process, but we want the APZCTMParent// for the parent process owning that content process. So we have to jump to// the LayerTreeState for the root layer tree id for that layer tree, and use// the mApzcTreeManagerParent from that. This should also work with nested// content processes, because RootLayerTreeId() will bypass any intermediate// processes' ids and go straight to the root.if(state){uint64_trootLayersId=state->mParent->RootLayerTreeId();itr=sIndirectLayerTrees.find(rootLayersId);state=(sIndirectLayerTrees.end()!=itr)?&itr->second:nullptr;}returnstate;}/* static */APZCTreeManagerParent*CompositorBridgeParent::GetApzcTreeManagerParentForRoot(uint64_taContentLayersId){MonitorAutoLocklock(*sIndirectLayerTreesLock);CompositorBridgeParent::LayerTreeState*state=GetStateForRoot(aContentLayersId,lock);returnstate?state->mApzcTreeManagerParent:nullptr;}/* static */GeckoContentController*CompositorBridgeParent::GetGeckoContentControllerForRoot(uint64_taContentLayersId){MonitorAutoLocklock(*sIndirectLayerTreesLock);CompositorBridgeParent::LayerTreeState*state=GetStateForRoot(aContentLayersId,lock);returnstate?state->mController.get():nullptr;}PTextureParent*CompositorBridgeParent::AllocPTextureParent(constSurfaceDescriptor&aSharedData,constLayersBackend&aLayersBackend,constTextureFlags&aFlags,constuint64_t&aId,constuint64_t&aSerial,constwr::MaybeExternalImageId&aExternalImageId){returnTextureHost::CreateIPDLActor(this,aSharedData,aLayersBackend,aFlags,aSerial,aExternalImageId);}boolCompositorBridgeParent::DeallocPTextureParent(PTextureParent*actor){returnTextureHost::DestroyIPDLActor(actor);}boolCompositorBridgeParent::IsSameProcess()const{returnOtherPid()==base::GetCurrentProcId();}#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)//#define PLUGINS_LOG(...) printf_stderr("CP [%s]: ", __FUNCTION__);// printf_stderr(__VA_ARGS__);// printf_stderr("\n");#define PLUGINS_LOG(...)boolCompositorBridgeParent::UpdatePluginWindowState(uint64_taId){MonitorAutoLocklock(*sIndirectLayerTreesLock);CompositorBridgeParent::LayerTreeState<s=sIndirectLayerTrees[aId];if(!lts.mParent){PLUGINS_LOG("[%"PRIu64"] layer tree compositor parent pointer is null",aId);returnfalse;}// Check if this layer tree has received any shadow layer updatesif(!lts.mUpdatedPluginDataAvailable){PLUGINS_LOG("[%"PRIu64"] no plugin data",aId);returnfalse;}// pluginMetricsChanged tracks whether we need to send plugin update// data to the main thread. If we do we'll have to block composition,// which we want to avoid if at all possible.boolpluginMetricsChanged=false;// Same layer tree checksif(mLastPluginUpdateLayerTreeId==aId){// no plugin data and nothing has changed, bail.if(!mCachedPluginData.Length()&&!lts.mPluginData.Length()){PLUGINS_LOG("[%"PRIu64"] no data, no changes",aId);returnfalse;}if(mCachedPluginData.Length()==lts.mPluginData.Length()){// check for plugin data changesfor(uint32_tidx=0;idx<lts.mPluginData.Length();idx++){if(!(mCachedPluginData[idx]==lts.mPluginData[idx])){pluginMetricsChanged=true;break;}}}else{// array lengths don't match, need to updatepluginMetricsChanged=true;}}else{// exchanging layer trees, we need to updatepluginMetricsChanged=true;}// Check if plugin windows are currently hidden due to scrollingif(mDeferPluginWindows){PLUGINS_LOG("[%"PRIu64"] suppressing",aId);returnfalse;}// If the plugin windows were hidden but now are not, we need to force// update the metrics to make sure they are visible again.if(mPluginWindowsHidden){PLUGINS_LOG("[%"PRIu64"] re-showing",aId);mPluginWindowsHidden=false;pluginMetricsChanged=true;}if(!lts.mPluginData.Length()){// Don't hide plugins if the previous remote layer tree didn't contain any.if(!mCachedPluginData.Length()){PLUGINS_LOG("[%"PRIu64"] nothing to hide",aId);returnfalse;}uintptr_tparentWidget=GetWidget()->GetWidgetKey();// We will pass through here in cases where the previous shadow layer// tree contained visible plugins and the new tree does not. All we need// to do here is hide the plugins for the old tree, so don't waste time// calculating clipping.mPluginsLayerOffset=nsIntPoint(0,0);mPluginsLayerVisibleRegion.SetEmpty();Unused<<lts.mParent->SendHideAllPlugins(parentWidget);lts.mUpdatedPluginDataAvailable=false;PLUGINS_LOG("[%"PRIu64"] hide all",aId);}else{// Retrieve the offset and visible region of the layer that hosts// the plugins, CompositorBridgeChild needs these in calculating proper// plugin clipping.LayerTransactionParent*layerTree=lts.mLayerTree;Layer*contentRoot=layerTree->GetRoot();if(contentRoot){nsIntPointoffset;nsIntRegionvisibleRegion;if(contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion,&offset)){// Check to see if these values have changed, if so we need to// update plugin window position within the window.if(!pluginMetricsChanged&&mPluginsLayerVisibleRegion==visibleRegion&&mPluginsLayerOffset==offset){PLUGINS_LOG("[%"PRIu64"] no change",aId);returnfalse;}mPluginsLayerOffset=offset;mPluginsLayerVisibleRegion=visibleRegion;Unused<<lts.mParent->SendUpdatePluginConfigurations(LayoutDeviceIntPoint::FromUnknownPoint(offset),LayoutDeviceIntRegion::FromUnknownRegion(visibleRegion),lts.mPluginData);lts.mUpdatedPluginDataAvailable=false;PLUGINS_LOG("[%"PRIu64"] updated",aId);}else{PLUGINS_LOG("[%"PRIu64"] no visibility data",aId);returnfalse;}}else{PLUGINS_LOG("[%"PRIu64"] no content root",aId);returnfalse;}}mLastPluginUpdateLayerTreeId=aId;mCachedPluginData=lts.mPluginData;returntrue;}voidCompositorBridgeParent::ScheduleShowAllPluginWindows(){MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::ShowAllPluginWindows",this,&CompositorBridgeParent::ShowAllPluginWindows));}voidCompositorBridgeParent::ShowAllPluginWindows(){MOZ_ASSERT(!NS_IsMainThread());mDeferPluginWindows=false;ScheduleComposition();}voidCompositorBridgeParent::ScheduleHideAllPluginWindows(){MOZ_ASSERT(CompositorLoop());CompositorLoop()->PostTask(NewRunnableMethod("layers::CompositorBridgeParent::HideAllPluginWindows",this,&CompositorBridgeParent::HideAllPluginWindows));}voidCompositorBridgeParent::HideAllPluginWindows(){MOZ_ASSERT(!NS_IsMainThread());// No plugins in the cache implies no plugins to manage// in this content.if(!mCachedPluginData.Length()||mDeferPluginWindows){return;}uintptr_tparentWidget=GetWidget()->GetWidgetKey();mDeferPluginWindows=true;mPluginWindowsHidden=true;#if defined(XP_WIN)// We will get an async reply that this has happened and then send hide.mWaitForPluginsUntil=TimeStamp::Now()+mVsyncRate;Unused<<SendCaptureAllPlugins(parentWidget);#elseUnused<<SendHideAllPlugins(parentWidget);ScheduleComposition();#endif}#endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)mozilla::ipc::IPCResultCompositorBridgeParent::RecvAllPluginsCaptured(){#if defined(XP_WIN)mWaitForPluginsUntil=TimeStamp();mHaveBlockedForPlugins=false;ForceComposeToTarget(nullptr);Unused<<SendHideAllPlugins(GetWidget()->GetWidgetKey());returnIPC_OK();#elseMOZ_ASSERT_UNREACHABLE("CompositorBridgeParent::RecvAllPluginsCaptured calls unexpected.");returnIPC_FAIL_NO_REASON(this);#endif}}// namespace layers}// namespace mozilla